﻿using Microsoft.VisualStudio.PlatformUI;
using Sasa.QualityTools.CodeAnalysis.Common;
using Sasa.QualityTools.CodeAnalysis.FxCopIntegrator.ViewModels;
using System;
using System.ComponentModel;
using System.Linq;
using System.Windows;

namespace Sasa.QualityTools.CodeAnalysis.FxCopIntegrator.UI
{
    public partial class CodeAnalysisProgressWindow : DialogWindow
    {
        private BackgroundWorker worker;


        public CodeAnalysisProgressWindow()
        {
            InitializeComponent();
        }


        protected override void OnContentRendered(EventArgs e)
        {
            base.OnContentRendered(e);

            Logger.Info("Began to perform code analysis.");

            var viewModel = (CodeAnalysisProgressViewModel)DataContext;
            if (viewModel.Analyses.Count() == 0)
            {
                Logger.Warn("FxCop Integrator have just stopped code analysis because it can't find a project that should be analyzed.");
                return;
            }

            worker = new BackgroundWorker();
            worker.WorkerSupportsCancellation = true;
            worker.DoWork += new DoWorkEventHandler(OnCodeAnalysisPerformed);
            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(OnCodeAnalysisCompleted);
            worker.RunWorkerAsync(viewModel);
        }

        protected override void OnClosing(CancelEventArgs e)
        {
            base.OnClosing(e);

            if (worker.IsBusy)
            {
                Logger.Info("Cancelled code analysis.");
                worker.CancelAsync();
            }
        }

        private void OnCodeAnalysisPerformed(object sender, DoWorkEventArgs e)
        {
            var worker = sender as BackgroundWorker;
            var viewModel = (CodeAnalysisProgressViewModel)e.Argument;

            foreach (var analysis in viewModel.Analyses)
            {
                if (analysis.Status == CodeAnalysisStatus.Skip)
                {
                    continue;
                }

                analysis.PerformCodeAnalysis();

                Dispatcher.Invoke(new Action(() =>
                {
                    foreach (var problem in analysis.Problems)
                    {
                        viewModel.Problems.Add(problem);
                    }
                    foreach (var rule in analysis.Rules)
                    {
                        viewModel.Rules.Add(rule);
                    }
                }));

                if (worker.CancellationPending)
                {
                    e.Cancel = true;
                    break;
                }
            }
        }

        private void OnCodeAnalysisCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            Logger.Info("Completed all code analysis processes.");

            Dispatcher.Invoke(new Action(() =>
            {
                var viewModel = (CodeAnalysisProgressViewModel)DataContext;

                if (e.Error != null)
                {
                    // TODO: send error report.
                    Logger.Error(e.Error, "Failed to analyze because an exception was thrown unexpectedly.");
                    var message = String.Join(Environment.NewLine,
                        "Failed to analyze because an exception was thrown unexpectedly.",
                        "",
                        "Exception : " + e.Error.GetType().FullName,
                        "Message : " + e.Error.Message);
                    MessageBox.Show(message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                    return;
                }

                var wasFailed = viewModel.Analyses.Where(o => o.Status == CodeAnalysisStatus.Failed).Count() > 0;
                if (e.Cancelled || wasFailed)
                {
                    return;
                }

                DialogResult = true;
            }));
        }

        private void Cancel(object sender, RoutedEventArgs e)
        {
            Close();
        }
    }
}
